package com.evil.application.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteUserDepartmentService;
import com.evil.account.api.RemoteUserEnterpriseService;
import com.evil.account.api.RemoteUserRoleService;
import com.evil.account.api.RemoteUserService;
import com.evil.application.convert.DataConvert;
import com.evil.application.enums.order.OrderSpecialControlEnum;
import com.evil.application.mapper.ApplicationPermissionMapper;
import com.evil.application.pojo.entity.ApplicationOrder;
import com.evil.application.pojo.entity.ApplicationPermission;
import com.evil.application.service.ApplicationPermissionService;
import com.evil.application.util.ApplicationOrderDataUtil;
import com.evil.common.account.dto.FindByIdAndEIdReqDTO;
import com.evil.common.account.dto.department.DepartmentBaseRespDTO;
import com.evil.common.account.dto.user.FindUserIdsByIdsReqDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.form.control.ControlBaseDTO;
import com.evil.common.application.dto.order.data.OrderIdControlIdDataReqDTO;
import com.evil.common.application.dto.permission.app.*;
import com.evil.common.application.enums.ApplicationSourceTypeEnum;
import com.evil.common.application.enums.permission.ApplicationPermissionTypeEnum;
import com.evil.common.application.enums.permission.PermissionStatusEnum;
import com.evil.common.application.enums.permission.PermissionVisibleEnum;
import com.evil.common.application.exception.ApplicationException;
import com.evil.common.core.dto.FindByIdReqDTO;
import com.evil.common.core.dto.FindByIdsReqDTO;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 应用权限表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@Service
@AllArgsConstructor
public class ApplicationPermissionServiceImpl extends ServiceImpl<ApplicationPermissionMapper, ApplicationPermission> implements ApplicationPermissionService {

    private final LoginUtil loginUtil;

    private final ApplicationOrderDataUtil applicationOrderDataUtil;

    private final ApplicationLogServiceImpl logService;

    private final RemoteUserService remoteUserService;

    private final RemoteUserRoleService remoteUserRoleService;

    private final RemoteUserDepartmentService remoteUserDepartmentService;

    private final RemoteUserEnterpriseService remoteUserEnterpriseService;

    /**
     * 应用权限
     *
     * @param sourceDTO appPermissionReqDTO
     * @return List
     */
    @Override
    public List<ApplicationPermission> findBySource(AppPermissionSourceDTO sourceDTO) {
        return this.baseMapper.findBySource(sourceDTO);
    }

    /**
     * 应用权限
     *
     * @param appPermissionsReqDTO appPermissionsReqDTO
     * @return List
     */
    @Override
    public List<ApplicationPermission> findByAppPermissions(AppPermissionsReqDTO appPermissionsReqDTO) {
        return this.baseMapper.findByAppPermissions(appPermissionsReqDTO);
    }

    /**
     * 获取应用权限
     *
     * @param source source
     * @return AppPermissionDTO 列表
     */
    @Override
    public List<AppPermissionDTO> findDTOBySource(AppPermissionSourceDTO source) {
        return this.permissionsToDTO(this.baseMapper.findBySource(source));
    }

    /**
     * 应用权限
     *
     * @param sourceTypeEnum sourceTypeEnum
     * @param sourceIds      sourceIds
     * @return Map（源id, 权限列表）
     */
    @Override
    public Map<Long, List<AppPermissionDTO>> findAppPermissionsBySource(ApplicationSourceTypeEnum sourceTypeEnum, Collection<Long> sourceIds) {
        return this.findAppPermissionsBySource(new AppPermissionsReqDTO(sourceTypeEnum, sourceIds));
    }

    /**
     * 应用权限
     *
     * @param appPermissionsReqDTO appPermissionsReqDTO
     * @return Map（源id, 权限列表）
     */
    @Override
    public Map<Long, List<AppPermissionDTO>> findAppPermissionsBySource(AppPermissionsReqDTO appPermissionsReqDTO) {
        List<ApplicationPermission> permissions = this.findByAppPermissions(appPermissionsReqDTO);
        return StreamUtil.groupK(this.permissionsToDTO(permissions), AppPermissionDTO::getSourceId);
    }

    /**
     * 获取应用权限
     *
     * @param sources sources
     * @return AppPermissionDTO 列表
     */
    @Override
    public Map<AppPermissionSourceDTO, List<AppPermissionDTO>> findDTOMapBySources(Collection<AppPermissionSourceDTO> sources) {
        List<ApplicationPermission> permissions = this.baseMapper.findBySources(sources);
        return StreamUtil.transMapV(StreamUtil.groupK(permissions, e -> new AppPermissionSourceDTO(e.getSourceType(), e.getSourceId())), this::permissionsToDTO);
    }

    /**
     * 应用权限
     *
     * @param appPermissionsReqDTO appPermissionsReqDTO
     * @return Map（源id, 权限列表）
     */
    @Override
    public Map<Long, List<AppPermissionDTO>> findDTOByAppPermissions(AppPermissionsReqDTO appPermissionsReqDTO) {
        List<ApplicationPermission> permissions = this.findByAppPermissions(appPermissionsReqDTO);
        return StreamUtil.groupK(this.permissionsToDTO(permissions), AppPermissionDTO::getSourceId);
    }

    /**
     * 获取应用权限的用户列表 角色/部门/动态 会转换成对应用户
     *
     * @param appPermissionSourceDTO appPermissionSourceDTO
     * @param isUse                  是否使用（过滤权限可见状态）
     * @return List
     */
    @Override
    public List<Long> getPermissionUserIdsBySource(AppPermissionSourceDTO appPermissionSourceDTO, Boolean isUse) {
        return this.getPermissionUsersBySource(appPermissionSourceDTO, isUse).stream().map(UserBaseRespDTO::getUserId).collect(Collectors.toList());
    }

    /**
     * 获取应用权限的用户列表 角色/部门/动态 会转换成对应用户
     *
     * @param appPermissionSourceDTO appPermissionSourceDTO
     * @param isUse                  是否使用（过滤权限可见状态）
     * @return List
     */
    @Override
    public List<UserBaseRespDTO> getPermissionUsersBySource(AppPermissionSourceDTO appPermissionSourceDTO, Boolean isUse) {
        Object dynamic = null;
        if (appPermissionSourceDTO instanceof AppPermissionUserReqDTO) {
            dynamic = ((AppPermissionUserReqDTO) appPermissionSourceDTO).getDynamic();
        }
        return this.getPermissionUsersByPermission(dynamic, this.findBySource(appPermissionSourceDTO), isUse);
    }

    /**
     * 获取应用权限的用户列表 角色/部门/动态 会转换成对应用户
     *
     * @param dynamic                dynamic
     * @param applicationPermissions applicationPermissions
     * @param isUse                  是否使用（过滤权限可见状态）
     * @return List
     */
    @Override
    public List<UserBaseRespDTO> getPermissionUsersByPermission(Object dynamic, Collection<ApplicationPermission> applicationPermissions, Boolean isUse) {
        List<AppPermissionDTO> appPermissions = this.permissionsToDTO(applicationPermissions);
        return this.getPermissionUsersByAppPermissionDTO(dynamic, appPermissions, isUse);
    }

    /**
     * 获取应用权限的用户列表 角色/部门/动态 会转换成对应用户
     *
     * @param dynamic        dynamic
     * @param appPermissions appPermissions
     * @param isUse          是否使用（过滤权限可见状态）
     * @return List
     */
    @Override
    public List<Long> getPermissionUserIdsByAppPermissionDTO(Object dynamic, Collection<AppPermissionDTO> appPermissions, Boolean isUse) {
        return this.getPermissionUsersByAppPermissionDTO(dynamic, appPermissions, isUse).stream().map(UserBaseRespDTO::getUserId).collect(Collectors.toList());
    }

    /**
     * 获取应用权限的用户列表 角色/部门/动态 会转换成对应用户
     *
     * @param dynamic        dynamic
     * @param appPermissions appPermissions
     * @param isUse          是否使用（过滤权限可见状态）
     * @return List
     */
    @Override
    public List<UserBaseRespDTO> getPermissionUsersByAppPermissionDTO(Object dynamic, Collection<AppPermissionDTO> appPermissions, Boolean isUse) {
        if (CollectionUtil.isEmpty(appPermissions)) {
            return new ArrayList<>();
        }
        // 用户ids，需要去重
        Set<Long> userIds = new HashSet<>();
        this.groupForEach(appPermissions, (type, list) -> {
            // 不过滤 / 使用 / 查看
            List<Long> targetIds;
            if (Objects.nonNull(isUse)) {
                Function<Integer, Boolean> filter = isUse ? PermissionVisibleEnum::isAvailable : PermissionVisibleEnum::isVisible;
                targetIds = StreamUtil.transListFT(list, p -> filter.apply(p.getVisible()), AppPermissionDTO::getTargetId);
            } else {
                targetIds = StreamUtil.transListT(list, AppPermissionDTO::getTargetId);
            }
            switch (ApplicationPermissionTypeEnum.isExistById(type)) {
                case USER:
                    // 用户
                    userIds.addAll(targetIds);
                    break;
                case DEPARTMENT:
                    // 部门
                    userIds.addAll(remoteUserDepartmentService.findUserIdsByDeptIds(FindByIdsReqDTO.filter(targetIds)));
                    break;
                case ROLE:
                    // 角色
                    userIds.addAll(remoteUserRoleService.findUserIdsByRoleIds(FindByIdsReqDTO.filter(targetIds)));
                    break;
                case DYNAMIC_APPLICANT:
                    // 申请人
                    if (null != dynamic) {
                        if (dynamic instanceof ApplicationOrder) {
                            Long orderApplicant = applicationOrderDataUtil.getOrderApplicant((ApplicationOrder) dynamic);
                            userIds.add(orderApplicant);
                        }
                    }
                    break;
                case DYNAMIC_DEPARTMENT_MANAGER:
                    // 动态部门主管--备注：该类型，实际上只能选择申请人控件、部门控件
                    if (null != dynamic) {
                        if (dynamic instanceof ApplicationOrder) {
                            List<Long> deptIds = new ArrayList<>();
                            // 获取订单
                            ApplicationOrder applicationOrder = (ApplicationOrder) dynamic;
                            targetIds.forEach(targetId -> {
                                if (OrderSpecialControlEnum.CREATOR.getId().equals(targetId)) {
                                    // 申请人--获取申请部门IDS
                                    Long orderApplicant = applicationOrderDataUtil.getOrderApplicant(applicationOrder);
                                    FindByIdAndEIdReqDTO filter = FindByIdAndEIdReqDTO.filterEId(orderApplicant, applicationOrder.getEnterpriseId());
                                    deptIds.addAll(remoteUserDepartmentService.findUserDepartmentByUserIds(filter));
                                } else {
                                    // 部门选择控件--获取控件值ids
                                    OrderIdControlIdDataReqDTO orderIdControlIdDataReqDTO = new OrderIdControlIdDataReqDTO(applicationOrder.getOrderId(), targetId);
                                    deptIds.addAll(applicationOrderDataUtil.getOrderControlDataId(orderIdControlIdDataReqDTO));
                                }
                            });
                            // 获取部门主管列表
                            userIds.addAll(remoteUserDepartmentService.findUserIdsByDeptIds(FindUserIdsByIdsReqDTO.filter(deptIds)));
                        }
                    }
                    break;
                case DYNAMIC_MEMBER_CONTROL:
                    // 动态成员控件
                    if (null != dynamic) {
                        if (dynamic instanceof ApplicationOrder) {
                            // 获取订单
                            ApplicationOrder applicationOrder = (ApplicationOrder) dynamic;
                            targetIds.forEach(targetId -> {
                                // 人员选择控件--获取控件值ids
                                OrderIdControlIdDataReqDTO orderIdControlIdDataReqDTO = new OrderIdControlIdDataReqDTO(applicationOrder.getOrderId(), targetId);
                                userIds.addAll(applicationOrderDataUtil.getOrderControlDataId(orderIdControlIdDataReqDTO));
                            });
                        }
                    }
                    break;
                case DYNAMIC_DEPARTMENT_CONTROL:
                    // 动态部门字段
                    if (null != dynamic) {
                        if (dynamic instanceof ApplicationOrder) {
                            List<Long> deptIds = new ArrayList<>();
                            // 获取订单
                            ApplicationOrder applicationOrder = (ApplicationOrder) dynamic;
                            targetIds.forEach(targetId -> {
                                // 部门选择控件--获取控件值ids
                                OrderIdControlIdDataReqDTO orderIdControlIdDataReqDTO = new OrderIdControlIdDataReqDTO(applicationOrder.getOrderId(), targetId);
                                deptIds.addAll(applicationOrderDataUtil.getOrderControlDataId(orderIdControlIdDataReqDTO));
                            });
                            // 获取部门人员列表
                            userIds.addAll(remoteUserDepartmentService.findUserIdsByDeptIds(FindByIdsReqDTO.filter(deptIds)));
                        }
                    }
                    break;
                default:
                    throw ApplicationPermissionTypeEnum.getBusinessException();
            }
        });
        if (CollectionUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        return remoteUserService.findBaseByIds(FindByIdsReqDTO.filter(userIds));
    }

    /**
     * 检查登录用户是否有权限
     *
     * @param enterpriseId           enterpriseId
     * @param permissionStatus       permissionStatus
     * @param appPermissionSourceDTO appPermissionSourceDTO
     * @param isUse                  是否使用（过滤权限可见状态）
     */
    @Override
    public void loginUserHasPermission_Check(Long enterpriseId, Integer permissionStatus, AppPermissionSourceDTO appPermissionSourceDTO, Boolean isUse) {
        if (!this.loginUserHasPermission(enterpriseId, permissionStatus, appPermissionSourceDTO, isUse)) {
            throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED);
        }
    }

    /**
     * 检查配置应用权限
     *
     * @param appPermissions appPermissions
     * @return List
     */
    @Override
    public boolean checkPermission(Collection<AppPermissionDTO> appPermissions) {
        DataConvert dataConvert = new DataConvert(loginUtil).initRoleMap().initDepartmentMap().initUserMap();
        AtomicBoolean success = new AtomicBoolean(true);
        StreamUtil.groupK(appPermissions, AppPermissionDTO::getPermissionType).forEach((type, list) -> {
            Set<Long> ids = list.stream().map(AppPermissionDTO::getTargetId).collect(Collectors.toSet());
            switch (ApplicationPermissionTypeEnum.isExistById(type)) {
                case ROLE:
                    if (ids.size() != dataConvert.getRoleBases(ids, true).size()) {
                        success.set(false);
                    }
                    break;
                case DEPARTMENT:
                    if (ids.size() != dataConvert.getDepartmentBases(ids, true).size()) {
                        success.set(false);
                    }
                    break;
                case USER:
                    if (ids.size() != dataConvert.getUserBases(ids, true).size()) {
                        success.set(false);
                    }
                    break;
            }
        });
        return success.get();
    }

    /**
     * 检查登录用户是否有权限
     *
     * @param appPermissionSourceDTO appPermissionSourceDTO
     * @param isUse                  是否使用（过滤权限可见状态）
     * @return boolean
     */
    @Override
    public boolean loginUserHasPermission(AppPermissionSourceDTO appPermissionSourceDTO, Boolean isUse) {
        return this.getPermissionUserIdsBySource(appPermissionSourceDTO, isUse).contains(loginUtil.getLoginUserId());
    }

    /**
     * 检查登录用户是否有权限
     *
     * @param dynamic        dynamic
     * @param appPermissions appPermissions
     * @param isUse          是否使用（过滤权限可见状态）
     * @return boolean
     */
    @Override
    public boolean loginUserHasPermission(Object dynamic, Collection<AppPermissionDTO> appPermissions, Boolean isUse) {
        return this.getPermissionUserIdsByAppPermissionDTO(dynamic, appPermissions, isUse).contains(loginUtil.getLoginUserId());
    }

    /**
     * 检查登录用户是否有权限
     *
     * @param enterpriseId           enterpriseId
     * @param permissionStatus       permissionStatus
     * @param appPermissionSourceDTO appPermissionSourceDTO
     * @param isUse                  是否使用（过滤权限可见状态）
     * @return boolean
     */
    @Override
    public boolean loginUserHasPermission(Long enterpriseId, Integer permissionStatus, AppPermissionSourceDTO appPermissionSourceDTO, Boolean isUse) {
        List<AppPermissionDTO> appPermissions = this.findDTOBySource(appPermissionSourceDTO);
        Object dynamic = null;
        if (appPermissionSourceDTO instanceof AppPermissionUserReqDTO) {
            dynamic = ((AppPermissionUserReqDTO) appPermissionSourceDTO).getDynamic();
        }
        return this.loginUserHasPermission(enterpriseId, permissionStatus, dynamic, appPermissions, isUse);
    }

    /**
     * 检查登录用户是否有权限
     *
     * @param enterpriseId     enterpriseId
     * @param permissionStatus permissionStatus
     * @param dynamic          dynamic
     * @param appPermissions   appPermissions
     * @param isUse            是否使用（过滤权限可见状态）
     * @return boolean
     */
    @Override
    public boolean loginUserHasPermission(Long enterpriseId, Integer permissionStatus, Object dynamic, Collection<AppPermissionDTO> appPermissions, Boolean isUse) {
        if (this.loginUserHasPermission(enterpriseId, permissionStatus)) {
            return true;
        }
        // 有权限
        return this.loginUserHasPermission(dynamic, appPermissions, isUse);
    }

    /**
     * 修改应用权限
     *
     * @param modifyAppPermissionReqDTO modifyAppPermissionReqDTO
     */
    @Override
    public void modifyPermission(ModifyAppPermissionReqDTO modifyAppPermissionReqDTO) {
        // 参数
        Long enterpriseId = loginUtil.getParamEnterpriseId(modifyAppPermissionReqDTO.getEnterpriseId());
        List<AppPermissionDTO> permissions = modifyAppPermissionReqDTO.getPermissions();
        Map<String, AppPermissionDTO> permissionMap = StreamUtil.toMapK(permissions, e -> this.permissionKey(e.getPermissionType(), e.getTargetId()));
        // 数据库
        List<ApplicationPermission> applicationPermissions = this.findBySource(modifyAppPermissionReqDTO);
        Map<String, ApplicationPermission> applicationPermissionMap = StreamUtil.toMapK(applicationPermissions, e -> this.permissionKey(e.getPermissionType(), e.getTargetId()));

        // 编辑/新增
        List<ApplicationPermission> modifies = permissions.stream().map(e -> {
            String key = this.permissionKey(e.getPermissionType(), e.getTargetId());
            if (applicationPermissionMap.containsKey(key)) {
                // 编辑
                ApplicationPermission applicationPermission = applicationPermissionMap.get(key);
                applicationPermission.setVisible(e.getVisible());
                applicationPermission.setPassword(e.getPassword());
                return applicationPermission;
            } else {
                // 新增
                return this.createApplicationPermission(enterpriseId, modifyAppPermissionReqDTO, e);
            }
        }).collect(Collectors.toList());

        // 删除
        modifies.addAll(applicationPermissions.stream()
                .filter(e -> !permissionMap.containsKey(this.permissionKey(e.getPermissionType(), e.getTargetId())))
                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                .collect(Collectors.toList()));

        logService.saveAndCheck(this.baseMapper, ApplicationPermission::getPermissionId, modifies);

    }

    /**
     * 复制应用权限
     *
     * @param copyAppPermissionReqDTO copyAppPermissionReqDTO
     * @return List
     */
    @Override
    public List<ApplicationPermission> copyPermission(CopyAppPermissionReqDTO copyAppPermissionReqDTO) {
        Long enterpriseId = copyAppPermissionReqDTO.getEnterpriseId();
        AppPermissionSourceDTO source = copyAppPermissionReqDTO.getSource();
        AppPermissionSourceDTO target = copyAppPermissionReqDTO.getTarget();
        Map<Long, Long> targetIdMap = copyAppPermissionReqDTO.getTargetIdMap();

        // 是否动态权限类型
        Function<ApplicationPermission, Boolean> isDynamic = p -> ApplicationPermissionTypeEnum.isExistById(p.getPermissionType()).isDynamic();
        // 是否动态处理人权限
        Function<ApplicationPermission, Boolean> dynamicHandler = p -> ApplicationPermissionTypeEnum.DYNAMIC_APPLICANT.getId() == p.getPermissionType();
        // 是否需要替换权限目标id
        Function<ApplicationPermission, Boolean> needReplace = p -> null != targetIdMap && targetIdMap.containsKey(p.getTargetId());

        List<ApplicationPermission> sourcePermissions = this.findBySource(source);
        List<ApplicationPermission> targetPermissions = this.findBySource(target);

        // 如果复制源是流程节点处理人 则非空判断
        if (ApplicationSourceTypeEnum.PROCESS_NODE_HANDLER.getId() == source.getSourceType()) {
            if (sourcePermissions.isEmpty()) {
                throw new ApplicationException();
            }
        }

        List<String> sourcePermissionKeys = new ArrayList<>();
        sourcePermissions.forEach(e -> {
            if (isDynamic.apply(e) && !dynamicHandler.apply(e) && needReplace.apply(e)) {
                // 动态权限 && 非动态处理人 && 需要替换目标id
                sourcePermissionKeys.add(this.permissionKey(e.getPermissionType(), targetIdMap.get(e.getTargetId())));
            } else {
                sourcePermissionKeys.add(this.permissionKey(e.getPermissionType(), e.getTargetId()));
            }
        });
        Map<String, ApplicationPermission> permissionMap = StreamUtil.toMapK(targetPermissions, e -> this.permissionKey(e.getPermissionType(), e.getTargetId()));

        // 新增
        List<ApplicationPermission> modifies = new ArrayList<>();
        sourcePermissions.forEach(e -> {
            String key = this.permissionKey(e.getPermissionType(), e.getTargetId());
            ApplicationPermission copy;
            if (permissionMap.containsKey(key)) {
                copy = permissionMap.get(key);
            } else {
                copy = new ApplicationPermission();
                copy.setEnterpriseId(enterpriseId);
                copy.setSourceType(target.getSourceType());
                copy.setSourceId(target.getSourceId());
            }
            copy.setPermissionType(e.getPermissionType());
            copy.setTargetId(e.getTargetId());
            copy.setPassword(e.getPassword());
            copy.setVisible(e.getVisible());
            if (isDynamic.apply(e) && !dynamicHandler.apply(e) && needReplace.apply(e)) {
                // 动态权限 && 非动态处理人 && 需要替换目标id
                copy.setTargetId(targetIdMap.get(e.getTargetId()));
            }
            modifies.add(copy);
        });

        // 删除
        targetPermissions.forEach(e -> {
            if (!sourcePermissionKeys.contains(this.permissionKey(e.getPermissionType(), e.getTargetId()))) {
                e.setIsDeleted(SwitchEnum.YES.getId());
                modifies.add(e);
            }
        });

        logService.saveAndCheck(this.baseMapper, ApplicationPermission::getPermissionId, modifies);
        return modifies;
    }

    /**
     * 删除权限
     *
     * @param sourceDTO sourceDTO
     */
    @Override
    public void deleteBySource(AppPermissionSourceDTO sourceDTO) {
        List<ApplicationPermission> permissions = this.findBySource(sourceDTO);
        permissions.forEach(e -> e.setIsDeleted(SwitchEnum.YES.getId()));
        logService.saveAndCheck(this.baseMapper, ApplicationPermission::getPermissionId, permissions);
    }

    /**
     * 处理app权限
     *
     * @param permissions permissions
     * @return Map 一层键permissionType，二层键sourceType，二层值targetId
     */
    @Override
    public Map<Integer, Map<Integer, Set<Long>>> convertAppPermission(List<AppPermissionDTO> permissions) {
        return StreamUtil.groupAndThenGroupTransSet(permissions, AppPermissionDTO::getPermissionType, AppPermissionDTO::getSourceType, AppPermissionDTO::getTargetId);
    }

    /**
     * 转换目标权限类型
     *
     * @param typeTargetIdMap typeTargetIdMap，一层键permissionType，二层键sourceType，二层值targetId
     * @return Map 一层键permissionType，二层键targetId，二层值target
     */
    @Override
    public Map<Integer, Map<Long, ?>> convertTypeTarget(Map<Integer, Map<Integer, Set<Long>>> typeTargetIdMap) {
        DataConvert dataConvert = new DataConvert(loginUtil)
                .initUserMap()
                .initDepartmentMap()
                .initRoleMap()
                .initControlMap();
        return StreamUtil.transMapV_Expand(typeTargetIdMap, (key, map) -> {
            Map<Long, Object> targetMap = new HashMap<>();
            map.forEach((sourceType, targetIds) -> {
                switch (ApplicationPermissionTypeEnum.isExistById(key)) {
                    case USER:
                        // 用户
                        targetMap.putAll(dataConvert.getUserBasesMap(targetIds, true));
                        break;
                    case DEPARTMENT:
                        // 部门
                        targetMap.putAll(dataConvert.getDepartmentBasesMap(targetIds, true));
                        break;
                    case ROLE:
                        // 角色
                        targetMap.putAll(dataConvert.getRoleBasesMap(targetIds, true));
                        break;
                    case DYNAMIC_APPLICANT:
                        // 动态申请人
                        if (ApplicationSourceTypeEnum.findById(sourceType) == ApplicationSourceTypeEnum.MEMBER_CONTROL_DEFAULT_VALUE) {
                            // 权限源为 成员控件默认值
                            UserBaseRespDTO loginUser = loginUtil.getLoginUserBase();
                            targetMap.putAll(StreamUtil.toMapV(targetIds, e -> loginUser));
                        } else {
                            // 其他权限源
                            targetMap.putAll(StreamUtil.toMapV(targetIds, e -> new DynamicTargetDTO(e, OrderSpecialControlEnum.CREATOR.getName())));
                        }
                    case DYNAMIC_DEPARTMENT_MANAGER:
                    case DYNAMIC_MEMBER_CONTROL:
                    case DYNAMIC_DEPARTMENT_CONTROL:
                        // 动态部门主管、动态成员控件、动态部门字段
                        List<ControlBaseDTO> controls = dataConvert.getControlBases(targetIds);
                        Map<Long, DynamicTargetDTO> controlTargetMap = StreamUtil.toMapKV(controls, ControlBaseDTO::getControlId,
                                e -> new DynamicTargetDTO(e.getControlId(), e.getControlTitle()));

                        OrderSpecialControlEnum creator = OrderSpecialControlEnum.CREATOR;
                        if (key == ApplicationPermissionTypeEnum.DYNAMIC_DEPARTMENT_MANAGER.getId()) {
                            // 是否动态部门主管权限
                            if (targetIds.contains(creator.getId())) {
                                controlTargetMap.put(creator.getId(), new DynamicTargetDTO(creator.getId(), creator.getName()));
                            }
                        }
                        targetMap.putAll(controlTargetMap);
                        break;
                    case DYNAMIC_DEPARTMENT:
                        // 当前登录人的部门
                        List<DepartmentBaseRespDTO> departmentBases = dataConvert.getLoginUserDepartmentBases();
                        targetMap.putAll(StreamUtil.toMapV(targetIds, e -> departmentBases));
                        break;
                    default:
                        throw ApplicationPermissionTypeEnum.getBusinessException();
                }
            });
            return targetMap;
        });
    }

    /**
     * 转DTO
     *
     * @param permissions permissions
     * @return AppPermissionDTO 列表
     */
    @Override
    public List<AppPermissionDTO> permissionsToDTO(Collection<ApplicationPermission> permissions) {
        Map<Integer, Map<Integer, Set<Long>>> typeTargetIdMap = StreamUtil.groupAndThenGroupTransSet(permissions,
                ApplicationPermission::getPermissionType, ApplicationPermission::getSourceType, ApplicationPermission::getTargetId);

        // 获取类型 目标对象
        Map<Integer, Map<Long, ?>> typeTargetMap = this.convertTypeTarget(typeTargetIdMap);

        return permissions.stream()
                .filter(e -> {
                    if (ApplicationPermissionTypeEnum.isDynamic(e.getPermissionType())) {
                        // 动态权限 如果目标 被删除，则权限失效不返回
                        return typeTargetMap.getOrDefault(e.getPermissionType(), new HashMap<>()).containsKey(e.getTargetId());
                    }
                    return true;
                })
                .map(e -> {
                    AppPermissionDTO p = this.toDTO(e);
                    p.setTarget(typeTargetMap.getOrDefault(e.getPermissionType(), new HashMap<>()).get(e.getTargetId()));
                    return p;
                }).collect(Collectors.toList());
    }

    /**
     * 校验权限密码
     *
     * @param appPermissionSourceDTO appPermissionSourceDTO
     * @param password               password
     */
    @Override
    public void checkPassword(AppPermissionSourceDTO appPermissionSourceDTO, String password) {
        Long loginUserId = loginUtil.getLoginUserId();
        List<AppPermissionDTO> permissions = this.findDTOBySource(appPermissionSourceDTO);

        // 不通过检验
        AtomicReference<Boolean> unPass = new AtomicReference<>();
        // ### 排序，先处理用户权限
        this.groupForEach(permissions, (type, list) -> {
            ApplicationPermissionTypeEnum permissionTypeEnum = ApplicationPermissionTypeEnum.isExistById(type);
            Predicate<AppPermissionDTO> filter;
            List<AppPermissionDTO> result;
            switch (permissionTypeEnum) {
                case USER:
                    // 用户
                    permissions.stream().filter(e -> e.getTargetId().equals(loginUserId)).findFirst().ifPresent(p -> {
                        unPass.set(!Objects.equals(p.getPassword(), password));
                        // ### 有为该用户单独配置权限，如果不通过，直接校验不通过
                        if (unPass.get()) {
                            throw new BusinessException(RCodeEnum.PASSWORD_ERROR);
                        }
                    });
                    break;
                case ROLE:
                    // 角色
                    filter = p -> StreamUtil.anyMatch(remoteUserRoleService.findUserIdsByRoleId(FindByIdReqDTO.filter(p.getTargetId())), e -> e.equals(loginUserId));
                    result = StreamUtil.filter(permissions, filter);
                    if (!result.isEmpty()) {
                        unPass.set(result.stream().noneMatch(p -> Objects.equals(p.getPassword(), password)));
                    }
                    break;
                case DEPARTMENT:
                    // 部门
                    filter = p -> StreamUtil.anyMatch(remoteUserDepartmentService.findUserIdsByDeptId(FindByIdReqDTO.filter(p.getTargetId())), e -> e.equals(loginUserId));
                    result = StreamUtil.filter(permissions, filter);
                    if (!result.isEmpty()) {
                        unPass.set(result.stream().noneMatch(p -> Objects.equals(p.getPassword(), password)));
                    }
                    break;
            }
        });
        // 没有操作权限
        if (null == unPass.get()) {
            throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED);
        }
        // 账号或密码错误
        if (unPass.get()) {
            throw new BusinessException(RCodeEnum.PASSWORD_ERROR);
        }
    }

    /**
     * 当前登录人是否有
     *
     * @param enterpriseId     enterpriseId
     * @param permissionStatus permissionStatus
     * @return boolean
     */
    private boolean loginUserHasPermission(Long enterpriseId, Integer permissionStatus) {
        // 不校验权限
        if (PermissionStatusEnum.ALL.getId() == permissionStatus) {
            return true;
        }
        // 是否总后台查看其他企业
        boolean admin = loginUtil.checkAdminEnterpriseOperate(enterpriseId);
        // 企业管理员
        boolean manager = remoteUserEnterpriseService.enterpriseManager(loginUtil.getLoginUserEnterprise());
        return admin || manager;
    }

    /**
     * 权限类型排序并分组 后 遍历
     *
     * @param permissions permissions
     * @param action      action
     */
    private void groupForEach(Collection<AppPermissionDTO> permissions, BiConsumer<Integer, List<AppPermissionDTO>> action) {
        StreamUtil.sortAndGroup(permissions, AppPermissionDTO::getPermissionType, AppPermissionDTO::getPermissionType).forEach(action);
    }

    /**
     * 应用权限唯一key 类型+目标id
     *
     * @param applicationPermissionType applicationPermissionType
     * @param targetId                  targetId
     * @return String
     */
    private String permissionKey(Integer applicationPermissionType, Long targetId) {
        return String.format("%s_%s", applicationPermissionType, targetId);
    }

    /**
     * 权限转DTO
     *
     * @param applicationPermission applicationPermission
     * @return AppPermissionDTO
     */
    private AppPermissionDTO toDTO(ApplicationPermission applicationPermission) {
        return BeanUtil.copyProperties(applicationPermission, AppPermissionDTO.class);
    }

    /**
     * 创建应用权限
     *
     * @param enterpriseId     enterpriseId
     * @param source           source
     * @param appPermissionDTO appPermissionsDTO
     * @return ApplicationPermission
     */
    private ApplicationPermission createApplicationPermission(Long enterpriseId, AppPermissionSourceDTO source, AppPermissionDTO appPermissionDTO) {
        ApplicationPermission applicationPermission = new ApplicationPermission();
        applicationPermission.setEnterpriseId(enterpriseId);
        applicationPermission.setSourceId(source.getSourceId());
        applicationPermission.setSourceType(source.getSourceType());
        applicationPermission.setTargetId(appPermissionDTO.getTargetId());
        applicationPermission.setPermissionType(appPermissionDTO.getPermissionType());
        applicationPermission.setPassword(appPermissionDTO.getPassword());

        return applicationPermission;
    }
}
